package com.mju.service.impl;

import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.connection.stream.MapRecord;
import org.springframework.data.redis.connection.stream.StreamOffset;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StreamOperations;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import com.mju.dao.SelectDurationMapper;
import com.mju.dao.SelectTeacherMapper;
import com.mju.exception.ServiceException;
import com.mju.model.SelectTeacher;
import com.mju.model.dto.ChoiceTeacherDTO;
import com.mju.model.dto.DurationDTO;
import com.mju.model.dto.SelectTeacherDTO;
import com.mju.service.SelectTeacherService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class SelectTeacherServiceImpl implements SelectTeacherService {

	@Autowired
	private RedisTemplate<String,String> redisTemplate;
	
	@Autowired
	private SelectTeacherMapper selectTeacherMapper;
//	
//	@Autowired
//	private TeacherMapper teacherMapper;
	@Autowired
	private SelectDurationMapper durationMapper;
	
	@Value("${custom.choiceRedisKey}")
	private String choiceRedisKey;
	
	//判断教师是否已满
	private boolean isFull(String teacherno) {
		List<ChoiceTeacherDTO> r=selectTeacherMapper.choicetotal(teacherno);
		if(r.size()==0) return false;
		
//		Object cstr=r.get(0).get("choiceTotal"); //当前选择数量		
//		Integer choiceTotal=Integer.valueOf(cstr.toString());
//		Integer limitnum=r.get(0).get("limitnum");//最多选择

		int choiceTotal=r.get(0).getChoiceTotal();
		int limitnum=r.get(0).getLimitNum();
		
		return (choiceTotal>=limitnum);
	}

	@Override
	public void dealChoice(String studentno, String msgId, Long time) throws ServiceException {
				
		SecurityContext context = SecurityContextHolder.getContext();
		String teacherno= context.getAuthentication().getName();
		this.dealChoice(teacherno, studentno, msgId, time);
	}
	
	@Override
	public void dealChoice(String teacherno, String studentno,String msgId,Long time) throws ServiceException {
		//判断是否该教师已满
		if(isFull(teacherno))
			throw new ServiceException(606, "指导学生已满");
		
		StreamOperations<String, String, String> opt= redisTemplate.opsForStream();
		//判断该生是否已经存在，是不操作，删除消息
		SelectTeacher student=selectTeacherMapper.selectByPrimaryKey(studentno);
		if(student!=null) {
			opt.delete(choiceRedisKey, msgId);
			throw new ServiceException(607, "该学生重复申请，换一个");
		}
		//获取选择的学期，用于存入数据库字段		
		DurationDTO dto=durationMapper.selectDuaration();
		Integer term=dto.getTerm();
		
		//正常加入数据库
		student=new SelectTeacher();
		student.setTerm(term);
		student.setSelecttime(new Date(time));
		student.setStudentno(studentno);
		student.setTeacherno(teacherno);
		selectTeacherMapper.insert(student);
		
		opt.delete(choiceRedisKey, msgId);
	}

	//学生选择当前登录导师确认选择清单
	@Override
	public List<SelectTeacherDTO> selectList() {
		SecurityContext context = SecurityContextHolder.getContext();
		String teacherno= context.getAuthentication().getName();
		return this.selectList(teacherno);
	}
	
	//学生选择某导师确认选择清单,注意，如果查询所有的，必须带参数为null或""
	@Override
	public List<SelectTeacherDTO> selectList(String teacherno) {		
		
		DurationDTO dto=durationMapper.selectDuaration();
		Integer term=dto.getTerm();
		
		SelectTeacher q=new SelectTeacher();
		q.setTeacherno(teacherno);
		q.setTerm(term);
		
		return selectTeacherMapper.selectList(q);
	}

	@Override
	public void autoChoiceTask() {
		//获取选择的学期，用于存入数据库字段		
		DurationDTO dto=durationMapper.selectDuaration();
		Integer term=dto.getTerm();
//		//获取所有教师
//		List<Teacher> teachers=teacherMapper.selectList();
		
//		//获取已经确认的学生
//		List<SelectTeacherDTO> selectedStudents=this.selectList("");
		StreamOperations<String, String, String> opt= redisTemplate.opsForStream();
		
		//第一轮，读取消息队列
		List<MapRecord<String,String,String>> result=					
				opt.read(StreamOffset.fromStart(choiceRedisKey));
		
		for(MapRecord<String,String,String> x:result) {
			String studentno=x.getValue().get("studentno");
			//判断该生是否已经确认，是删除消息
			SelectTeacher student=selectTeacherMapper.selectByPrimaryKey(studentno);
			if(student!=null) {
				opt.delete(choiceRedisKey,x.getId());
				continue;
			}
			//判断第一志愿教师是否已满
			String teacherno=x.getValue().get("teacher1");
			if(isFull(teacherno)) continue;//进入第二轮
			//正常加入数据库
			saveSelectStudent(term,x.getId().getTimestamp(),studentno,teacherno);
			opt.delete(choiceRedisKey,x.getId());
		}

		//进入第二轮自动处理，获取消息队列所有学生志愿
		List<MapRecord<String,String,String>> redisMsg=
				opt.read(StreamOffset.fromStart(choiceRedisKey));
		for(MapRecord<String,String,String> x:redisMsg) {
			String studentNo=x.getValue().get("studentno");
			String teacherNo=x.getValue().get("teacher2");//第二志愿
			//判断该教师是否已满
			if(isFull(teacherNo)) continue;//进入剩余未匹配处理
			saveSelectStudent(term, x.getId().getTimestamp(), studentNo, teacherNo);
			opt.delete(choiceRedisKey, x.getId());//删除已处理的消息
		}

		//进入剩余未匹配处理,获取所有教师选择情况，去掉已经满的
		List<ChoiceTeacherDTO> selectedTeachers=selectTeacherMapper.choicetotal("");
		//删除已满教师
		Iterator<ChoiceTeacherDTO> it=selectedTeachers.iterator();
		while(it.hasNext()) {
			ChoiceTeacherDTO c=it.next();
			if(c.getChoiceTotal()>=c.getLimitNum()) it.remove();
		}

		List<MapRecord<String,String,String>> redisMsgs=
				opt.read(StreamOffset.fromStart(choiceRedisKey));
		for(MapRecord<String,String,String> x:redisMsgs) {
			String studentNo=x.getValue().get("studentno");
			String teacherNo=x.getValue().get("teacher2");//第二志愿
			while(it.hasNext()) {
				ChoiceTeacherDTO c=it.next();
				if(c.getTeacherNo().equals(teacherNo)) {
					c.setChoiceTotal(c.getChoiceTotal()+1);
					saveSelectStudent(term, x.getId().getTimestamp(), studentNo, teacherNo);
					opt.delete(choiceRedisKey, x.getId());//删除已处理的消息
					if(c.getChoiceTotal()>=c.getLimitNum()) it.remove();
				}
			}
		}
	}
	
	private void saveSelectStudent(int term,Long d,String studentno,String teacherno) {
		SelectTeacher student=new SelectTeacher();
		student.setTerm(term);
		student.setSelecttime(new Date(d));
		student.setStudentno(studentno);
		student.setTeacherno(teacherno);
		selectTeacherMapper.insert(student);
	}
}
